package com.xyzwps.lib.beans;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Objects;

public record PropertyInfo(String name, Type type, Field field,
                           Getter getter, Setter setter,
                           boolean readable, boolean writable,
                           Class<?> beanClass
) {
    public PropertyInfo {
        Objects.requireNonNull(beanClass);
        Objects.requireNonNull(name);
        Objects.requireNonNull(type);

        if (getter == null && setter == null) {
            throw new IllegalArgumentException("There should be at least one of getter or setter.");
        }
    }


    /// Get the first annotation satisfying the predicate. The search order is field, getter, setter.
    /// May be null if no annotation is found.
    ///
    /// 获取满足断言的第一个注解。搜索顺序是先字段，再 getter，最后 setter。若找不到，则返回 null。
    ///
    /// @return the first annotations satisfying the predicate.
    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        var field = field();
        if (field != null) {
            var anno = field.getAnnotation(annotationClass);
            if (anno != null) {
                return anno;
            }
        }

        if (readable()) {
            var anno = getter().method().getAnnotation(annotationClass);
            if (anno != null) {
                return anno;
            }
        }

        if (writable()) {
            var anno = setter().method().getAnnotation(annotationClass);
            if (anno != null) {
                return anno;
            }
        }

        return null;
    }

    /// Get property value through getter, not property field.
    ///
    /// 通过 getter（而非字段）获取属性值。
    ///
    /// @param object which holding the property value. 持有属性值的对象。
    /// @return the get result. 获取属性值的结果。
    public GetResult get(Object object) {
        if (readable()) {
            return getter().get(object);
        }
        return GetResult.NOT_READABLE;
    }

    /// Set property value through setter, not property field.
    ///
    /// 通过 setter（而非字段）设置属性值。
    ///
    /// @param object which set the property value to. 把属性值放到哪个对象中。
    /// @param value  would be set into first param. 会被设置到第一个参数中。
    /// @return the set result. 设置属性值的结果。
    public SetResult set(Object object, Object value) {
        if (writable()) {
            try {
                return setter().set(object, PropertySetHelper.toSettableValue(value, type()));
            } catch (Exception e) {
                return SetResult.failed(e);
            }
        }
        return SetResult.NOT_WRITABLE;
    }

}
